#include "httpconn.h"
bool Httpconn::isET_;
char* Httpconn::srcDir_;
std::atomic<int> Httpconn::usercount_;
Httpconn::Httpconn()
    :fd_(-1),
    isclose_(true)
{
    bzero(&Client_,sizeof(Client_));
}
Httpconn::~Httpconn()
{
    Close();
}
int Httpconn::getFd()
{
    return fd_;
}

const char * Httpconn::getIP()
{
    return inet_ntoa(Client_.sin_addr);
}
uint16_t Httpconn::getPort()
{
    return ntohs(Client_.sin_port);
}
void Httpconn::getAddr(sockaddr_in& sockaddr)
{
    sockaddr = Client_;
}
void Httpconn::init(int fd,const sockaddr_in& client)
{
    assert(fd > 0);
    isclose_ =false;
    fd_ = fd;
    Client_ = client;
    usercount_ +=1;
    readBuff_.makezero();
    writeBuff_.makezero();
    //fd[x] IP:port n
    LOG_INFO("Client[%d](%s:%d) in,nUser:%d",fd_,getIP(),getPort(),(int)usercount_);
}
void Httpconn::Close()
{
    //解除 mmap 映射
    respon_.UnmapFile_();
    if(isclose_ == false)
    {
        isclose_ = true;
        usercount_ -=1;
        close(fd_);
        LOG_INFO("Client[%d](%s:%d) in,nUser:%d",fd_,getIP(),getPort(),(int)usercount_);
    }
}
ssize_t Httpconn::read(int *Errno)
{
    ssize_t len = -1;
    do
    {
        len = readBuff_.readFromdFd(fd_,Errno);
        if(len <=0) {break;}
    } while (isET_);

    return len;
}
ssize_t Httpconn::write(int *Errno)
{
    ssize_t len = -1;
    do
    {
        len = writev(fd_,io_,iocnt_);
        if(len <=0)
        {
            *Errno = errno;
            break;
        }
        //传输完毕
        if( (io_[0].iov_len + io_[1].iov_len) == 0) {   break;  } 
        //传输未完毕 但剩余的数据长度比较小 准备下一次的传输

        //io[0] 为 响应行 + 响应头
        //io[1] 为 响应体 // html文本信息 //通过 mmap内存映射而来
        else if(static_cast<size_t>(len) > io_[0].iov_len)  
        {//已经读完 相应行+响应头信息 TCP缓存不够 / Fd 缓存不够
            //用 unit8_t* 是因为 这里要移动 char*指针   I/O
            io_[1].iov_base = (uint8_t*)io_[1].iov_base + (len - io_[0].iov_len);
            io_[1].iov_len = io_[1].iov_len - (len - io_[0].iov_len);
            if(io_[0].iov_len)
            {
                writeBuff_.makezero();
                io_[0].iov_len = 0;
            }
        }
        //剩余的数据很多
        else
        {

           io_[0].iov_base = (uint8_t*)io_[0].iov_base + len;
           io_[0].iov_len -=len;
           writeBuff_.HasRead(len);//
        }
    } while (isET_ || TotalWBytes() > 10240);
    //假设 一次http解析最长为1'0240个字节
    return len;
}
//进行 解析 + 响应工作
bool Httpconn::process()
{
    reques_.init();
    if(readBuff_.readableBytes() <= 0)
    {
        return false;
    }
    else if(reques_.Parse(readBuff_))
    {//解析成功
        //LOG_DEBUG("prepare read %s",reques_.path().c_str());
        respon_.Init(srcDir_,reques_.path(),reques_.isKeepAlive(),200);
    }
    else
    {//解析失败
        //没有进行截断 表明是因为什原因解析失败
        respon_.Init(srcDir_,reques_.path(),false,400);
    }

    //开始制作相应报文
    respon_.MakeResponce(writeBuff_);
    //结构为 响应头 + 响应体（html等文件中的信息）
    io_[0].iov_base = static_cast<char*>(writeBuff_.Begin_ptr());
    io_[0].iov_len = writeBuff_.readableBytes();
    iocnt_ = 1;

    //如果需要发送响应体
    if((respon_.GetfileLen_() >0) && (respon_.GetFile_()!=nullptr))
    {
        iocnt_ = 2;
        //File 为通过 mmap 映射的文件内存域
        //与 writeBuff 结构无关
        io_[1].iov_base = respon_.GetFile_();
        io_[1].iov_len = respon_.GetfileLen_();
    }
    LOG_DEBUG("FileSize:%d,%d to %d",respon_.GetfileLen_(),iocnt_,TotalWBytes());
    return true;
}